home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / utils / sound / players / unix / rplay / rplayd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-23  |  8.3 KB  |  427 lines

  1. /*
  2.  * rplayd.c
  3.  *
  4.  * Copyright (c) 1992 by Mark Boyns
  5.  *
  6.  * Permission to use, copy, modify, and distribute this software and its
  7.  * documentation for any purpose and without fee is hereby granted, provided
  8.  * that the above copyright notice appear in all copies and that both that
  9.  * copyright notice and this permission notice appear in supporting
  10.  * documentation.  This software is provided "as is" without express or
  11.  * implied warranty.
  12.  */
  13.  
  14. #include <sys/types.h>
  15. #include <sys/time.h>
  16. #include <sys/file.h>
  17. #include <sys/param.h>
  18. #include <sys/stat.h>
  19. #include <sys/mman.h>
  20. #include <sys/socket.h>
  21. #include <sys/signal.h>
  22. #include <sys/fcntl.h>
  23. #include <lwp/lwp.h>
  24. #include <lwp/stackdep.h>
  25. #include <netinet/in.h>
  26. #include <stdio.h>
  27. #include <search.h>
  28. #include <strings.h>
  29. #include "libst.h"
  30. #include "rplay.h"
  31.  
  32. /*
  33.  * The defines below can be used to customize rplayd.
  34.  */
  35. #define MAX_SOUNDS        1024    /* maximum sounds that rplayd can handle */
  36.                     /* this must be more than the sounds in rplay.conf */
  37. #define SPOOL_SIZE        8    /* number of sounds that can be played at once */
  38. #define SOUND_LIST_SIZE        32    /* maximum size of a sound list */
  39. #define AUDIO_BUFSIZE        500    /* rplayd audio buffer size */
  40. #define TIME_SLICE        50000    /* micro seconds */
  41. #define RPLAYD_TIMEOUT        6000     /* 50000usec = 1/20sec, 20*5*60 = 5 mins */
  42. #define AUDIO_CLOSE_TIMEOUT    100    /* close audio device when not in use */
  43.                     /* 50000usec = 1/20sec, 20*5 = 5 secs */
  44.  
  45. /*
  46.  * These should not be changed
  47.  */
  48. #define MINPRIO            1
  49. #define MAXPRIO            10
  50. #define SUN_AUDIO_DEVICE    "/dev/audio"
  51. #define SUN_MAGIC        0x2e736e64
  52. #define SUN_HDRSIZE        24
  53.  
  54. typedef struct sound {
  55.     char    *name;            /* name of the sound file */
  56.     char    path[MAXPATHLEN];    /* pathname of the sound file */
  57.     char    *buf;            /* the sound buffer */
  58.     char    *start;            /* where to start */
  59.     char    *stop;            /* where to stop */
  60.      int    size;            /* sizeof the sound buffer */
  61. } Sound;
  62.  
  63. typedef struct spool {
  64.     int    nsounds;        /* nsounds in the sound list */
  65.     int    curr;            /* current playing sound in the list */
  66.     int    state;            /* state of the current sound */
  67.     Sound    *slist[SOUND_LIST_SIZE];/* the sound list */
  68.     int    vlist[SOUND_LIST_SIZE];    /* the volume list */
  69.     char    *ptr;            /* sound buffer pointer */
  70.     char    *end;            /* the end of the sound buffer */
  71. } Spool;
  72.  
  73. Spool    spool[SPOOL_SIZE];        /* the sound spool */
  74. Sound    *list[SOUND_LIST_SIZE];     /* temporary list used by the server */
  75. char    recvbuf[MAX_PACKET];        /* buffer for incoming packets */
  76.  
  77. ENTRY    *hsearch();
  78. Sound    *lookup();
  79. int    scheduler(), player(), server();
  80. int    in = 0, out = 0;
  81. int    audio_fd = -1;
  82.  
  83. main()
  84. {
  85.     config();
  86.     spool_init();
  87.  
  88.     pod_setmaxpri(MAXPRIO);
  89.     lwp_setstkcache(4096, 4);
  90.     lwp_create((thread_t *)0, scheduler, MAXPRIO, 0, lwp_newstk(), 0);
  91.     lwp_create((thread_t *)0, player, MINPRIO, 0, lwp_newstk(), 0);
  92.     lwp_create((thread_t *)0, server, MINPRIO, 0, lwp_newstk(), 0);
  93.  
  94.     exit(0);
  95. }
  96.  
  97. config()
  98. {
  99.     Sound    *s;
  100.     ENTRY    e;
  101.     FILE    *fp;
  102.     char    buf[MAXPATHLEN], *p;
  103.  
  104.     fp = fopen(RPLAY_CONF, "r");
  105.     if (fp == NULL) {
  106.         fprintf(stderr, "rplayd: cannot open %s\n", RPLAY_CONF);
  107.         exit(1);
  108.     }
  109.  
  110.     if (hcreate(MAX_SOUNDS) == 0) {
  111.         fprintf(stderr, "rplayd: cannot create hash table\n");
  112.         exit(1);
  113.     }
  114.  
  115.     while(fgets(buf, sizeof(buf), fp) != NULL) {
  116.         if (buf[0] == '#') {
  117.             continue;
  118.         }
  119.  
  120.         s = (Sound *)malloc(sizeof(Sound));
  121.         sscanf(buf, "%s", s->path);
  122.         p = rindex(s->path, '/');
  123.         s->name = p == NULL ? s->path : p+1;
  124.         s->buf = NULL;
  125.         s->size = 0;
  126.  
  127.         e.key = s->name;
  128.         e.data = (char *)s;
  129.         if (hsearch(e, ENTER) == NULL) {
  130.             fprintf(stderr, "rplayd: the hash table is full, too many sounds\n");
  131.             exit(1);
  132.         }
  133.     }
  134.  
  135.     fclose(fp);
  136. }
  137.  
  138. spool_init()
  139. {
  140.     int    i;
  141.  
  142.     for(i = 0; i < SPOOL_SIZE; i++) { 
  143.         spool_clear(i);
  144.     }
  145. }
  146.  
  147. Sound    *lookup(name)
  148. char    *name;
  149. {
  150.     ENTRY        e, *found;
  151.     Sound        *s;
  152.  
  153.     e.key = name;
  154.     found = hsearch(e, FIND);
  155.     if (found == NULL) {
  156.         return NULL;
  157.     }
  158.  
  159.     s = (Sound *)found->data;
  160.  
  161.     if (s->buf == NULL) {
  162.         struct stat    st;
  163.         long        magic, hdr_size;
  164.         int        fd;
  165.  
  166.         fd = open(s->path, O_RDONLY, 0);
  167.         if (fd < 0) {
  168.             return NULL;
  169.         }
  170.  
  171.         if (fstat(fd, &st) < 0) {
  172.             return NULL;
  173.         }
  174.  
  175.         s->size = st.st_size;
  176.  
  177.         /*
  178.          * use mmap to load the sound
  179.          */
  180.         s->buf = mmap(0, s->size, PROT_READ, MAP_SHARED, fd, 0);
  181.         if (s->buf == (caddr_t)-1) {
  182.             return NULL;
  183.         }
  184.  
  185.         /*
  186.          * make sure it is a Sun audio file
  187.          */
  188.         magic = *((long *)s->buf);
  189.         if (magic != SUN_MAGIC) {
  190.             return NULL;
  191.         }
  192.  
  193.         /*
  194.          * ignore the header
  195.          */
  196.         hdr_size = *((long *)s->buf + 1);
  197.         if (hdr_size < SUN_HDRSIZE) {
  198.             return NULL;
  199.         }
  200.  
  201.         s->start = s->buf + hdr_size;
  202.         s->stop = s->buf + s->size - 1;
  203.  
  204.         close(fd);
  205.     }
  206.  
  207.     return s;
  208. }
  209.  
  210. server()
  211. {
  212.     int            sock_fd, x, restarted, len;
  213.     struct sockaddr_in    s, f;
  214.     int            flen = sizeof(f);
  215.     char            *p;
  216.     int            attr, i, n, j;   
  217.     int            found;
  218.     Sound            *sound;
  219.  
  220. #ifdef INETD
  221.     sock_fd = 0;
  222. #else
  223.     bzero(&s, sizeof(s));
  224.     s.sin_family = AF_INET;
  225.     s.sin_port = htons(RPLAY_PORT);
  226.     s.sin_addr.s_addr = INADDR_ANY;
  227.  
  228.     sock_fd = socket(AF_INET, SOCK_DGRAM, 0);
  229.     if (sock_fd < 0) {
  230.         perror("socket");
  231.         pod_exit(1);
  232.     }
  233.  
  234.     if (bind(sock_fd, &s, sizeof(s)) < 0) {
  235.         perror("bind");
  236.         pod_exit(1);
  237.     }
  238. #endif INETD
  239.  
  240.     for(;;) {
  241.         len = recvfrom(sock_fd, recvbuf, sizeof(recvbuf), 0, &f, &flen);
  242.         p = recvbuf;
  243.         attr = *p++;
  244.         switch(attr) {
  245.         case RPLAY_PLAY:
  246.             for(i = 0; i < SPOOL_SIZE; i++) {
  247.                 if (spool[i].state == RPLAY_NULL) {
  248.                     break;
  249.                 }          
  250.             } 
  251.             if (i == SPOOL_SIZE) {
  252.                 break;
  253.             }
  254.             do {
  255.                 sound = lookup(p);  
  256.                 if (sound == NULL) {
  257.                     spool_clear(i);
  258.                     break;
  259.                 }
  260.                 p += strlen(p) + 1; 
  261.                 spool[i].slist[spool[i].nsounds] = sound;   
  262.                 spool[i].vlist[spool[i].nsounds] = (unsigned char)*p++;
  263.                 spool[i].nsounds++;
  264.             } while(*p != NULL);
  265.             if (sound != NULL) {
  266.                 spool[i].ptr = spool[i].slist[0]->start;
  267.                 spool[i].end = spool[i].slist[0]->stop;
  268.                 spool[i].curr = 0;
  269.                 spool[i].state = attr;   
  270.                 in++;
  271.             }
  272.             break;
  273.  
  274.         case RPLAY_STOP: 
  275.         case RPLAY_PAUSE:
  276.         case RPLAY_CONTINUE:
  277.             n = 0;  
  278.             do {
  279.                 list[n] = lookup(p);   
  280.                 if (list[n] == NULL) {
  281.                     break;
  282.                 } 
  283.                 n++;
  284.                 p += strlen(p) + 1; 
  285.             } while(*p != NULL);
  286.             if (list[n-1] == NULL) {
  287.                 break;
  288.             }
  289.             for(i = 0; i < SPOOL_SIZE; i++) {
  290.                 if (spool[i].nsounds == n) {
  291.                     found = 1;
  292.                     for(j = 0; j < n; j++) { 
  293.                          if (list[j] != spool[i].slist[j]) {
  294.                             found = 0;         
  295.                             break;
  296.                         } 
  297.                     } 
  298.                     if (found) {
  299.                         spool[i].state = attr;
  300.                         break;
  301.                     } 
  302.                 }
  303.             }
  304.             break;
  305.  
  306.         default:
  307.             fprintf(stderr, "rplayd: unknown rplay attribute (0x%0x)\n", attr);  
  308.             break;
  309.         }
  310.     }
  311. }
  312.  
  313. scheduler()
  314. {
  315.     struct timeval    t;
  316.     int        cnt;
  317.  
  318.     cnt = 0;
  319.     t.tv_sec = 0;
  320.     t.tv_usec = TIME_SLICE;
  321.  
  322.     for(;;) {
  323.         if (in == out) {
  324.             cnt++;
  325.             switch(cnt) {
  326.             case RPLAYD_TIMEOUT:
  327.                 pod_exit(0);
  328.  
  329.             case AUDIO_CLOSE_TIMEOUT:
  330.                 if (audio_fd != -1) {
  331.                     close(audio_fd);
  332.                     audio_fd = -1;
  333.                 }
  334.                 break;
  335.             }
  336.         }
  337.         else {
  338.             cnt = 0;
  339.         }
  340.         lwp_sleep(&t);
  341.         lwp_resched(MINPRIO);
  342.     }
  343. }
  344.  
  345. player()
  346. {
  347.     int    i, index, empty;
  348.     long    total; 
  349.     long    val;
  350.     char    buf[AUDIO_BUFSIZE];
  351.  
  352.     index = 0;
  353.  
  354.     for(;;) {
  355.         total = 0; 
  356.         empty = 1;
  357.         for(i = 0; i < SPOOL_SIZE; i++) { 
  358.             switch(spool[i].state) { 
  359.             case RPLAY_CONTINUE: 
  360.                 spool[i].state = RPLAY_PLAY;
  361.             case RPLAY_PLAY:
  362.                 empty = 0;
  363.                 val = st_ulaw_to_linear((unsigned char)*spool[i].ptr) * spool[i].vlist[spool[i].curr];  
  364.                 total += val >> 7;
  365.                 if (spool[i].ptr == spool[i].end) {
  366.                     spool[i].curr++;
  367.                     if (spool[i].curr == spool[i].nsounds) {  
  368.                         spool_clear(i);
  369.                         out++; 
  370.                     }  
  371.                     else {  
  372.                         spool[i].ptr = spool[i].slist[spool[i].curr]->start; 
  373.                         spool[i].end = spool[i].slist[spool[i].curr]->stop; 
  374.                     }
  375.                 } 
  376.                 else {
  377.                     spool[i].ptr++;
  378.                 }
  379.                 break; 
  380.             
  381.             case RPLAY_STOP:
  382.                 spool_clear(i);
  383.                 out++;
  384.                 break;
  385.                 
  386.             default:
  387.                 break;
  388.             }
  389.         }
  390.  
  391.         if (empty) {
  392.             if (index > 0) {
  393.                 if (audio_fd == -1) {
  394.                     audio_fd = open(SUN_AUDIO_DEVICE, O_WRONLY | O_NDELAY, 0);
  395.                 }
  396.                 if (audio_fd != -1) {
  397.                     write(audio_fd, buf, index);
  398.                 }
  399.                 index = 0;
  400.             }
  401.             lwp_yield(SELF);
  402.         }
  403.         else {
  404.             buf[index++] = st_linear_to_ulaw(total);
  405.             if (index == AUDIO_BUFSIZE) {
  406.                 if (audio_fd == -1) {
  407.                     audio_fd = open(SUN_AUDIO_DEVICE, O_WRONLY | O_NDELAY, 0);
  408.                 }
  409.                 if (audio_fd != -1) {
  410.                     write(audio_fd, buf, index);
  411.                 }
  412.                 index = 0;
  413.             }
  414.         }
  415.     }
  416. }
  417.  
  418. spool_clear(i)
  419. int    i;
  420. {
  421.     spool[i].curr = 0;
  422.     spool[i].nsounds = 0;
  423.     spool[i].ptr = NULL;
  424.     spool[i].end = NULL;
  425.     spool[i].state = RPLAY_NULL;
  426. }
  427.